#!/usr/bin/env python3

# create a domain trust

import sys
from optparse import OptionParser

sys.path.insert(0, "bin/python")

import samba
import samba.getopt as options
from samba.dcerpc import lsa, security, drsblobs
from samba.ndr import ndr_pack
from samba import arcfour_encrypt, string_to_byte_array
import random

########### main code ###########
if __name__ == "__main__":
    parser = OptionParser("createtrust [options] server")
    sambaopts = options.SambaOptions(parser)
    credopts = options.CredentialsOptionsDouble(parser)
    parser.add_option_group(credopts)

    (opts, args) = parser.parse_args()

    lp = sambaopts.get_loadparm()
    creds = credopts.get_credentials(lp)

    if len(args) != 1:
        parser.error("You must supply a server")

    if not creds.authentication_requested():
        parser.error("You must supply credentials")

    server = args[0]

    binding_str = "ncacn_np:%s[print]" % server

    lsaconn = lsa.lsarpc(binding_str, lp, creds)

    objectAttr = lsa.ObjectAttribute()
    objectAttr.sec_qos = lsa.QosInfo()

    pol_handle = lsaconn.OpenPolicy2(''.decode('utf-8'),
                                     objectAttr, security.SEC_FLAG_MAXIMUM_ALLOWED)

    name = lsa.String()
    name.string = "sub2.win2k3.obed.home.abartlet.net"
    try:
        info = lsaconn.QueryTrustedDomainInfoByName(pol_handle, name, lsa.LSA_TRUSTED_DOMAIN_INFO_FULL_INFO)

        lsaconn.DeleteTrustedDomain(pol_handle, info.info_ex.sid)
    except RuntimeError:
        pass

    info = lsa.TrustDomainInfoInfoEx()
    info.domain_name.string = "sub2.win2k3.obed.home.abartlet.net"
    info.netbios_name.string = "sub2"
    info.sid = security.dom_sid("S-1-5-21-538090388-3760119675-95745416")
    info.trust_direction = lsa.LSA_TRUST_DIRECTION_INBOUND | lsa.LSA_TRUST_DIRECTION_OUTBOUND
    info.trust_type = lsa.LSA_TRUST_TYPE_UPLEVEL
    info.trust_attributes = lsa.LSA_TRUST_ATTRIBUTE_WITHIN_FOREST

    password_blob = string_to_byte_array("password".encode('utf-16-le'))

    clear_value = drsblobs.AuthInfoClear()
    clear_value.size = len(password_blob)
    clear_value.password = password_blob

    clear_authentication_information = drsblobs.AuthenticationInformation()
    clear_authentication_information.LastUpdateTime = 0
    clear_authentication_information.AuthType = lsa.TRUST_AUTH_TYPE_CLEAR
    clear_authentication_information.AuthInfo = clear_value

    version_value = drsblobs.AuthInfoVersion()
    version_value.version = 1

    version = drsblobs.AuthenticationInformation()
    version.LastUpdateTime = 0
    version.AuthType = lsa.TRUST_AUTH_TYPE_VERSION
    version.AuthInfo = version_value

    authentication_information_array = drsblobs.AuthenticationInformationArray()
    authentication_information_array.count = 2
    authentication_information_array.array = [clear_authentication_information, version]

    outgoing = drsblobs.trustAuthInOutBlob()
    outgoing.count = 1
    outgoing.current = authentication_information_array

    trustpass = drsblobs.trustDomainPasswords()
    confounder = [3] * 512

    for i in range(512):
        confounder[i] = random.randint(0, 255)

    trustpass.confounder = confounder

#    print "confounder: ", trustpass.confounder

    trustpass.outgoing = outgoing
    trustpass.incoming = outgoing

    trustpass_blob = ndr_pack(trustpass)

#    print "trustpass_blob: ", list(trustpass_blob)

    encrypted_trustpass = arcfour_encrypt(lsaconn.session_key, trustpass_blob)

#    print "encrypted_trustpass: ", list(encrypted_trustpass)

    auth_blob = lsa.DATA_BUF2()
    auth_blob.size = len(encrypted_trustpass)
    auth_blob.data = string_to_byte_array(encrypted_trustpass)

    auth_info = lsa.TrustDomainInfoAuthInfoInternal()
    auth_info.auth_blob = auth_blob


#    print "auth_info.auth_blob.data: ", auth_info.auth_blob.data

    trustdom_handle = lsaconn.CreateTrustedDomainEx2(pol_handle,
                                                     info,
                                                     auth_info,
                                                     security.SEC_STD_DELETE)
